package ca.qc.bdeb.jeuxdesboites;

import ca.qc.bdeb.jeuxdesboites.commun.Coup;
import ca.qc.bdeb.utilitaires.Direction;
import ca.qc.bdeb.jeuxdesboites.commun.EvenementPartie;
import ca.qc.bdeb.jeuxdesboites.commun.IDJoueurs;
import ca.qc.bdeb.jeuxdesboites.model.GestionPartie;
import ca.qc.bdeb.jeuxdesboites.model.TableauJeu;
import ca.qc.bdeb.mvc.Observateur;
import ca.qc.bdeb.event.ComponentSelectedEvent;
import ca.qc.bdeb.event.ComponentSelectedListener;
import ca.qc.bdeb.graphiques.Sprite;
import ca.qc.bdeb.graphiques.UtilitairesImages;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/**
 * Cette classe dessine le tableau de jeu et gère les coups fait par le joueur
 * humain.
 * 
 * @author Eric Wenaas <eric.wenaas@bdeb.qc.ca>
 * @version 0.3
 */
final class JeuxGUI extends JPanel implements ComponentSelectedListener,
                                              Observateur {

    private static final int LARGEUR_POINT = 8;
    private static final int HAUTEUR_POINT = 8;
    private static final int ESPACE_POINT_BARRE = 1;
    
    private GestionPartie jeu;
    private TableauJeu tableau;
    private Sprite[][] points;
    private LinkedList<BarreSprite> barres;
    private JLabel[][] etiquettesBoites;

    JeuxGUI() {
        setLayout(null);
    }
    
    /**
     * Place le jeu. La partie doit avoir été initialisée afin de placer
     * correctement les éléments du jeu.
     * 
     * @param leJeu
     */
    void setJeu(GestionPartie leJeu) {
        if (jeu != null) {
            detruireComposants(); // Les anciens elements d'interface doivent être
                              // supprimés.
        }
        jeu = leJeu;
        tableau = leJeu.getTableau();
        points = new Sprite[jeu.LARGEUR_TABLEAU + 1][jeu.HAUTEUR_TABLEAU + 1];
        barres = new LinkedList<>();
        etiquettesBoites = new JLabel[jeu.LARGEUR_TABLEAU][jeu.HAUTEUR_TABLEAU];
        creerPoints();
        creerEtiquettesBoites();
        creerBarresHorizontales();
        creerBarresVerticales();
        repaint();
    }
    
    private void detruireComposants() {
        for (Sprite tabPoints[] : points) {
            for(Sprite point : tabPoints) {
                remove(point);
            }
        }
        points = null;
        
        for (JLabel tabProprietaires[] : etiquettesBoites) {
            for(JLabel label : tabProprietaires) {
                remove(label);
            }
        }
        etiquettesBoites = null;
        
        while (! barres.isEmpty()) {
            remove(barres.removeFirst());
        }
        barres = null;
    }
    
    private void creerPoints() {
        BufferedImage dotImage =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/dot.png"));
        double horizontalGap = (getWidth() - LARGEUR_POINT) / (double) jeu.LARGEUR_TABLEAU;
        double verticalGap = (getHeight() - HAUTEUR_POINT) / (double) jeu.HAUTEUR_TABLEAU;

        for (int i = 0; i < jeu.LARGEUR_TABLEAU + 1; i++) {
            for (int j = 0; j < jeu.HAUTEUR_TABLEAU + 1; j++) {
                points[i][j] = new Sprite(dotImage);
                points[i][j].setSize(LARGEUR_POINT, HAUTEUR_POINT);
                points[i][j].setLocation((int) (i * horizontalGap),
                                         (int) (j * verticalGap));
                points[i][j].setVisible(true);
                add(points[i][j]);
            }
        }
    }
    
    // TODO: Centrer les étiquettes à l'intérieur de la boîte.
    private void creerEtiquettesBoites() {
        for (int x = 0; x < jeu.LARGEUR_TABLEAU; x++) {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU; y++) {
                int xGauche = points[x][y].getLocation().x + ESPACE_POINT_BARRE + LARGEUR_POINT;
                int xDroit = points[x+1][y].getLocation().x - LARGEUR_POINT;
                int largeur = xDroit - xGauche;
                int xPosition = xGauche + (largeur - 120) / 2;
                int yHaut = points[x][y].getLocation().y + ESPACE_POINT_BARRE + LARGEUR_POINT;
                int yBas = points[x][y + 1].getLocation().y - ESPACE_POINT_BARRE;
                int hauteur = yBas - yHaut;
                int yPosition = yHaut + (hauteur - 50) / 2; 
                
                JLabel nouvelleEtiquette = new JLabel("", SwingConstants.CENTER);
                nouvelleEtiquette.setSize(120, 50);
                nouvelleEtiquette.setLocation(xPosition, yPosition);
                add(nouvelleEtiquette);
                etiquettesBoites[x][y] = nouvelleEtiquette;
            }
        }
    }

    private void creerBarresHorizontales()
    {
        BufferedImage horizontalImage =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/bar.png"));

        for (int x = 0; x < jeu.LARGEUR_TABLEAU; x++)
        {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU + 1; y++)
            {
                int xPosition = points[x][y].getLocation().x + ESPACE_POINT_BARRE + LARGEUR_POINT;
                int yPosition = points[x][y].getLocation().y;
                int width = points[x + 1][y].getLocation().x - ESPACE_POINT_BARRE - xPosition;
                Coup pos;
                if (y == 0) {
                    pos = new Coup(x, y, Direction.HAUT);
                } else {
                    pos = new Coup(x, y - 1, Direction.BAS);
                }
                BarreSprite nouveauSprite = new BarreSprite(horizontalImage, pos);
                nouveauSprite.setSize(width, HAUTEUR_POINT);
                nouveauSprite.setLocation(xPosition, yPosition);
                nouveauSprite.addComponentSelectedListener(this);
                add(nouveauSprite);
                barres.add(nouveauSprite);
            }
        }
    }
    private void creerBarre()
    {
        
    }
    private void creerBarresVerticales() {
        BufferedImage verticalImage =
                UtilitairesImages.creerImage4Octets(getClass().getResource("/Images/bar.png"));
        UtilitairesImages.faireRotation(verticalImage, 90);
        for (int x = 0; x < jeu.LARGEUR_TABLEAU + 1; x++) {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU; y++) {
                int xPosition = points[x][y].getLocation().x;
                int yPosition = points[x][y].getLocation().y + ESPACE_POINT_BARRE + HAUTEUR_POINT;
                int height = points[x][y + 1].getLocation().y - ESPACE_POINT_BARRE - yPosition;
                Coup pos;
                if (x == 0) {
                    pos = new Coup(x, y, Direction.GAUCHE);
                } else {
                    pos = new Coup(x - 1, y, Direction.DROIT);
                }
                BarreSprite nouveauSprite = new BarreSprite(verticalImage, pos);
                nouveauSprite.setSize(LARGEUR_POINT, height);
                nouveauSprite.setLocation(xPosition, yPosition);
                nouveauSprite.addComponentSelectedListener(this);
                add(nouveauSprite);
                barres.add(nouveauSprite);
            }
        }
    }
    
    private void mettreAJour() {
        mettreAJourBarres();
        mettreAJourNoms();
    }
    
    private void mettreAJourBarres() {
        IDJoueurs joueurActuel = jeu.getJoueurActuel();
        boolean humainAJouer = joueurActuel.equals(IDJoueurs.JOUEUR_HUMAIN);
        for (BarreSprite sprite : barres) {
            Coup c = sprite.getPosition();
            int x = c.positionX;
            int y = c.positionY;
            Direction d = c.direction;
            if (tableau.isFermee(x, y, d)) {
                sprite.fermerBarre();
            } else {
                sprite.ouvrirBarre();
            }
            if (humainAJouer) {
                sprite.activerBarre();
            } else {
                sprite.desactiverBarre();
            }
        }
    }
    
    private void mettreAJourNoms() {
        String nomAI = jeu.getNomJoueur(IDJoueurs.JOUEUR_ARTIFICIEL);
        String nomHumain = jeu.getNomJoueur(IDJoueurs.JOUEUR_HUMAIN);
        for (int x = 0; x < jeu.LARGEUR_TABLEAU; x++) {
            for (int y = 0; y < jeu.HAUTEUR_TABLEAU; y++) {
                IDJoueurs joueur = tableau.getProprietaire(x, y);
                if (joueur != null) {  
                    String nom = joueur.equals(IDJoueurs.JOUEUR_ARTIFICIEL) ? nomAI : nomHumain;
                    etiquettesBoites[x][y].setText(nom);
                }
            }
        }
    }
    
    void activerDesactiverCoups() {
        boolean humainAJouer = jeu.getJoueurActuel().equals(IDJoueurs.JOUEUR_HUMAIN);
        for (BarreSprite sprite: barres) {
                if (humainAJouer) {
                    sprite.activerBarre();
                } else {
                    sprite.desactiverBarre();
                }
            }
    }
    
    // Méthodes de l'interface ComponentSelectedListener
    @Override
    public void onComponentSelectedEvent(ComponentSelectedEvent evt) {
        BarreSprite sprite = (BarreSprite) (evt.getSource());
        Coup leCoup = sprite.getPosition();
        jeu.jouerCoup(IDJoueurs.JOUEUR_HUMAIN, leCoup);
    }

    // Méthodes de l'interface Observateur
    @Override
    public void changementEtat() {
        mettreAJour();
    }

    @Override
    public void changementEtat(Enum<?> property, Object o) {
        if (property.equals(EvenementPartie.COUPS_REQUIS)) {
            activerDesactiverCoups();
        }
    }
}
